/*
 Copyright (C) 2010 Chris Hawkins. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
 
 * Redistributions of source code must retain the above copyright notice, this
 list of conditions and the following disclaimer.
 
 * Neither the name of the author nor the names of its contributors may be used
 to endorse or promote products derived from this software without specific
 prior written permission.
 
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#import "ConfigManager.h"
#import "AsdNotification.h"

@implementation TASDConfigManager

#pragma mark -- NSObject standard
- (id)                              init {
    self = [super init];
    if ( self != nil ) {
        dictValues     = [[NSMutableDictionary alloc] initWithCapacity: 20];   
    }
    return self;
}
- (void)                            dealloc {
    [dictValues             release];
    [providerEndpoint       release];
    [providerSignature      release];
    [providerDataDomain     release];
    [providerDataDomainItem release];
    [super dealloc];
}
#pragma mark -- Save / Restore
- (NSString*)                       archivePath {
    NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *path    = [NSString stringWithFormat: @"%@/Configuration.plist", docPath];
    return path;
}
- (void)                            archiveRestore {
    NSString* path    = [[self archivePath] retain];
    NSData* plistData = [[NSData dataWithContentsOfFile: path ] retain];
    if ( plistData != nil ) {
        NSString*               error       = nil;
        NSPropertyListFormat    plistFormat = 0;
        id                      plistId     = [NSPropertyListSerialization propertyListFromData: plistData 
                                                                               mutabilityOption: NSPropertyListImmutable 
                                                                                         format: &plistFormat 
                                                                               errorDescription: &error];
        if ( plistId != nil ) {
            NSObject* plistObj = plistId;
            [plistObj retain];
            if ( plistFormat == NSPropertyListXMLFormat_v1_0 || plistFormat == NSPropertyListBinaryFormat_v1_0 ) {
                if ( [plistObj isKindOfClass: [NSDictionary class]] ) {
                    [dictValues addEntriesFromDictionary: (NSDictionary*) plistObj];
                }
            }
            [plistObj release];
        }
        [error     release];
    }
    [plistData release];
    [path      release];
}
- (void)                            archiveSave {
    NSString*   error       = nil;
    NSData*     plistData   = [[NSPropertyListSerialization dataFromPropertyList: dictValues 
                                                                          format: NSPropertyListXMLFormat_v1_0 
                                                                errorDescription: &error] retain];
    if ( plistData != nil ) {
        [plistData writeToFile: [self archivePath] atomically: YES];
    }
    [plistData release];
    [error     release];
}
#pragma mark -- TASD_ConfigSink 
- (void)                            setValueKey: (NSString*) valueKey_ forProvider: (NSObject<TASD_ConfigProvider>*) provider_ {
    NSString* storeKey         = [provider_ valueKey];
    NSString* currentValueKey  = [dictValues valueForKey: storeKey];
    if ( ![currentValueKey isEqual: valueKey_] ) {
        [dictValues setValue: valueKey_ forKey: [provider_ valueKey]];   
        [ASDSpNotification postIdleNotificationByName: [TASDConfigManager kNotification] object: provider_];
        [self archiveSave];
    }
}
- (NSString*)                       valueKeyForProvider: (NSObject<TASD_ConfigProvider>*) provider_ {
    if ( 0 == [dictValues count] ) {
        [self archiveRestore];
    }
    NSString* valueKey = [dictValues valueForKey: [provider_ valueKey]];
    if ( valueKey == nil ) {
        valueKey = [provider_ defaultValueKey];
        [self archiveSave];
    }
    return valueKey;
}
- (NSObject*)                       valueForProvider: (NSObject<TASD_ConfigProvider>*) provider_ {
    NSString* valueKey = [dictValues valueForKey: [provider_ valueKey]];
    if ( valueKey == nil ) {
        valueKey = [provider_ defaultValueKey];
    }
    return [[provider_ choices] valueForKey: valueKey];
}
#pragma mark -- TASD_ConfigProvider accessors
- (NSObject<TASD_ConfigProvider>*)  providerAwsEndpoint {
    if ( providerEndpoint == nil ) {
        providerEndpoint = [[TASDConfigProvEndpoint alloc] init];
    }
    return providerEndpoint;
}
- (NSObject<TASD_ConfigProvider>*)  providerAwsSignature {
    if ( providerSignature == nil ) {
        providerSignature = [[TASDConfigProvSignature alloc] init];
        [providerSignature setInitialValues];
    }
    return providerSignature;
}
- (NSObject<TASD_ConfigProvider>*)  providerDomain {
    if ( providerDataDomain == nil ) {
        providerDataDomain = [[TASDConfigProvDataDomain alloc] init];
    }
    return providerDataDomain;
}
- (NSObject<TASD_ConfigProvider>*)  providerDomainAttribute {
    DASDDomain  *domain = (DASDDomain*) [self valueForProvider: [self providerDomain]];
    if ( providerDataDomainAttribute != nil ) {
        if ( [domain entryCode] != [[providerDataDomainAttribute domain] entryCode] ) {
            [providerDataDomainAttribute release];
            providerDataDomainAttribute = nil;
        }
    }
    if ( providerDataDomainAttribute == nil ) {
        providerDataDomainAttribute = [[TASDConfigProvDataDomainAttribute alloc] initWithDomain: domain];
    }
    return providerDataDomainAttribute;
}
- (NSObject<TASD_ConfigProvider>*)  providerDomainItem {
    DASDDomain  *domain = (DASDDomain*) [self valueForProvider: [self providerDomain]];
    if ( providerDataDomainItem != nil ) {
        if ( [domain entryCode] != [[providerDataDomainItem domain] entryCode] ) {
            [providerDataDomainItem release];
            providerDataDomainItem = nil;
        }
    }
    if ( providerDataDomainItem == nil ) {
        providerDataDomainItem = [[TASDConfigProvDataDomainItem alloc] initWithDomain: domain];
    }
    return providerDataDomainItem;
}
- (NSObject<TASD_ConfigProvider>*)  providerDomainItemCount {
    DASDDomain  *domain = (DASDDomain*) [self valueForProvider: [self providerDomain]];
    if ( providerDataDomainItemCount != nil ) {
        if ( [domain entryCode] != [[providerDataDomainItemCount domain] entryCode] ) {
            [providerDataDomainItemCount release];
            providerDataDomainItemCount = nil;
        }
    }
    if ( providerDataDomainItemCount == nil ) {
        providerDataDomainItemCount = [[TASDConfigProvDataDomainItemCount alloc] initWithDomain: domain];
    }
    return providerDataDomainItemCount;
}
- (NSObject<TASD_ConfigProvider>*)  providerSelect {
    if ( providerDataSelect == nil ) {
        providerDataSelect = [[TASDConfigProvDataSelect alloc] init];
    }
    return providerDataSelect;
}
#pragma mark -- NSNotification
+ (NSString*)                       kNotification {
    return @"ASDTConfigManager_Notification";
}
@end
